package com.inkegz.highlight.utils

import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.text.style.ImageSpan
import com.facebook.common.executors.CallerThreadExecutor
import com.facebook.common.references.CloseableReference
import com.facebook.datasource.DataSource
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
import com.facebook.imagepipeline.image.CloseableImage
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.google.gson.Gson
import com.google.gson.JsonParser
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import kotlinx.coroutines.suspendCancellableCoroutine
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.*

val Int.dp: Int                 // [xxhdpi](360 -> 1080)
    get() = android.util.TypedValue.applyDimension(
            android.util.TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics
    ).toInt()

class RawJsonAdapter : TypeAdapter<String>() {
    override fun write(out: JsonWriter?, value: String?) {
        out?.jsonValue(value)
    }

    override fun read(reader: JsonReader?): String {
        return JsonParser().parse(reader).toString()
    }
}

inline fun Boolean.isTrue(block: () -> Unit) = also {
    if (it)
        block()
}

inline fun Boolean.isFalse(block: () -> Unit) = also {
    if (!it)
        block()
}

inline fun <reified T> fromJson(json: String): T? {
    return fromJson(json, T::class.java)
}

fun <T> fromJson(json: String, classOfT: Class<T>): T? {
    return try {
        Gson().fromJson(json, classOfT)
    } catch (ex: Exception) {
        null
    }
}

class ListParameterizedType constructor(private val type: Type) : ParameterizedType {
    override fun getActualTypeArguments(): Array<Type> {
        return arrayOf(type)
    }

    override fun getRawType(): Type {
        return ArrayList::class.java
    }

    override fun getOwnerType(): Type? {
        return null
    }

}

suspend fun getFrescoImageSpan(imageUrl: String, width: Int): ImageSpan? {
    return suspendCancellableCoroutine {
        val imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageUrl)).build()
        val imagePipeline = Fresco.getImagePipeline()
        val dataSource = imagePipeline.fetchDecodedImage(imageRequest, imageUrl)
        dataSource.subscribe(object : BaseBitmapDataSubscriber() {
            override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
                it.resumeWith(Result.success(null))
            }

            override fun onNewResultImpl(bitmap: Bitmap?) {
                bitmap?.also { b ->
                    val copy = b.copy(b.config, b.isMutable)
                    val bitmapDrawable = BitmapDrawable(copy)
                    it.resumeWith(
                            Result.success(
                                    CenterAlignImageSpan(
                                            bitmapDrawable.apply {
                                                if (width > 0) setBounds(0, 0, width, width)
                                            },
                                            CenterAlignImageSpan.ALIGN_CENTER
                                    )
                            )
                    )
                } ?: run {
                    it.resumeWith(Result.success(null))
                }
            }
        }, CallerThreadExecutor.getInstance())
    }
}